﻿using PubSubGeneric.WCFContracts;
using Serialize.Linq.Nodes;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;

namespace PubSubGeneric.WCFSubcriptionServer
{
    public class WCFSubscriptionServiceAdapter : IWCFSubscriptionServiceAdapter
    {
        SubscriptionService subscriptionservice = new SubscriptionService();
        //MethodInfo SubscribeMI;
        MethodInfo SubscribeWithExpressionMI;
        //MethodInfo UnSubscribeMI;
        MethodInfo UnSubscribeWithExpressionMI;

        public WCFSubscriptionServiceAdapter()
        {
            MethodInfo[] Methods = subscriptionservice.GetType().GetMethods();

            //SubscribeMI = Methods.Where(p => p.Name.Equals("Subscribe") &&
            //     p.IsGenericMethod == true && p.GetParameters().Count() == 2).Single();

            SubscribeWithExpressionMI = Methods.Where(p => p.Name.Equals("Subscribe") &&
                 p.IsGenericMethod == true && p.GetParameters().Count() == 3).Single();

            //UnSubscribeMI = Methods.Where(p => p.Name.Equals("UnSubscribe") &&
            //     p.IsGenericMethod == true && p.GetParameters().Count() == 2).Single();

            UnSubscribeWithExpressionMI = Methods.Where(p => p.Name.Equals("UnSubscribe") &&
                 p.IsGenericMethod == true && p.GetParameters().Count() == 3).Single();

        }

        public void Subscribe(string topic, string typeName)
        {
            Subscribe(topic, null, typeName);
        }

        public void Subscribe(string topic, ExpressionNode predicate, string typeName)
        {
            Type t = Type.GetType(typeName);
            MethodInfo GenericSubscribeWithExpressionMI = SubscribeWithExpressionMI.MakeGenericMethod(new Type[] { t });

            Type wcfSubscriberType = typeof(WCFSubscriberAdapter<>);
            var makeme = wcfSubscriberType.MakeGenericType(t);
            object wcfSubscriberInstance = Activator.CreateInstance(makeme);

            IWCFSubscriber subscriber = OperationContext.Current.GetCallbackChannel<IWCFSubscriber>();
            (wcfSubscriberInstance as IWCFSubscriberAdapter).WCFSubscriber = subscriber;

            GenericSubscribeWithExpressionMI.Invoke(subscriptionservice, new object[] { topic, wcfSubscriberInstance, (predicate == null ? null : predicate.ToExpression()) });
        }

        public void UnSubscribe(string topic, string typeName)
        {
            UnSubscribe(topic, null, typeName);
        }

        public void UnSubscribe(string topic, ExpressionNode predicate, string typeName)
        {
            Type t = Type.GetType(typeName);
            MethodInfo GenericUnSubscribeMI = UnSubscribeWithExpressionMI.MakeGenericMethod(new Type[] { t });

            Type wcfSubscriberType = typeof(WCFSubscriberAdapter<>);
            var makeme = wcfSubscriberType.MakeGenericType(t);
            object wcfSubscriberInstance = Activator.CreateInstance(makeme);

            IWCFSubscriber subscriber = OperationContext.Current.GetCallbackChannel<IWCFSubscriber>();
            (wcfSubscriberInstance as IWCFSubscriberAdapter).WCFSubscriber = subscriber;

            GenericUnSubscribeMI.Invoke(subscriptionservice, new object[] { topic, wcfSubscriberInstance, (predicate == null ? null : predicate.ToExpression()) });
        }
    }
}
